In [177]:
print("Projekt wykonali:\n- Kamil Skałbania\n- Paweł Wypych\n- Miłosz Gronowski")
Projekt wykonali:
- Kamil Skałbania
- Paweł Wypych
- Miłosz Gronowski
In [178]:
import pandas as pd
import numpy as np
data = pd.read_csv("song_data.csv")

print(data.columns)
Index(['song_name', 'song_popularity', 'song_duration_ms', 'acousticness',
       'danceability', 'energy', 'instrumentalness', 'key', 'liveness',
       'loudness', 'audio_mode', 'speechiness', 'tempo', 'time_signature',
       'audio_valence'],
      dtype='object')
In [179]:
data.head(50)
Out[179]:
song_name song_popularity song_duration_ms acousticness danceability energy instrumentalness key liveness loudness audio_mode speechiness tempo time_signature audio_valence
0 Boulevard of Broken Dreams 73 262333 0.005520 0.496 0.682 0.000029 8 0.0589 -4.095 1 0.0294 167.060 4 0.4740
1 In The End 66 216933 0.010300 0.542 0.853 0.000000 3 0.1080 -6.407 0 0.0498 105.256 4 0.3700
2 Seven Nation Army 76 231733 0.008170 0.737 0.463 0.447000 0 0.2550 -7.828 1 0.0792 123.881 4 0.3240
3 By The Way 74 216933 0.026400 0.451 0.970 0.003550 0 0.1020 -4.938 1 0.1070 122.444 4 0.1980
4 How You Remind Me 56 223826 0.000954 0.447 0.766 0.000000 10 0.1130 -5.065 1 0.0313 172.011 4 0.5740
5 Bring Me To Life 80 235893 0.008950 0.316 0.945 0.000002 4 0.3960 -3.169 0 0.1240 189.931 4 0.3200
6 Last Resort 81 199893 0.000504 0.581 0.887 0.001110 4 0.2680 -3.659 0 0.0624 90.578 4 0.7240
7 Are You Gonna Be My Girl 76 213800 0.001480 0.613 0.953 0.000582 2 0.1520 -3.435 1 0.0855 105.046 4 0.5370
8 Mr. Brightside 80 222586 0.001080 0.330 0.936 0.000000 1 0.0926 -3.660 1 0.0917 148.112 4 0.2340
9 Sex on Fire 81 203346 0.001720 0.542 0.905 0.010400 9 0.1360 -5.653 1 0.0540 153.398 4 0.3740
10 The Middle 78 168253 0.042400 0.629 0.897 0.000000 2 0.2630 -3.401 1 0.0483 161.944 4 0.9300
11 Numb 63 185586 0.004600 0.496 0.863 0.000000 9 0.6390 -4.153 1 0.0381 110.018 4 0.2430
12 Smooth Criminal 75 209266 0.004340 0.647 0.964 0.003600 9 0.1500 -4.225 0 0.0600 126.942 4 0.8750
13 Can't Stop 81 269000 0.017900 0.618 0.938 0.000000 9 0.1670 -3.442 1 0.0456 91.455 4 0.8750
14 Chop Suey! 69 210240 0.000353 0.420 0.929 0.000747 7 0.1220 -3.899 0 0.1210 127.204 4 0.3000
15 Take Me Out 77 237026 0.000423 0.278 0.676 0.000899 9 0.1360 -8.821 1 0.0371 104.545 4 0.4940
16 I Miss You 71 227240 0.001360 0.659 0.778 0.000007 11 0.0841 -6.423 1 0.0379 110.022 4 0.6230
17 Best of You 62 256600 0.007010 0.370 0.944 0.000003 1 0.1350 -4.979 0 0.0767 130.315 4 0.3450
18 I Write Sins Not Tragedies 77 187613 0.093800 0.567 0.795 0.000000 9 0.1140 -4.985 0 0.1340 170.060 4 0.6350
19 Kryptonite 79 233933 0.006640 0.545 0.865 0.000011 11 0.1680 -5.708 0 0.0286 99.010 4 0.5430
20 The Kill (Bury Me) 69 231533 0.001400 0.309 0.912 0.000271 4 0.5820 -3.881 0 0.0646 183.035 3 0.3020
21 Use Somebody 79 230760 0.005520 0.276 0.715 0.000417 0 0.2010 -5.356 1 0.0432 137.028 4 0.1730
22 No One Knows 13 255066 0.013700 0.518 0.538 0.000398 0 0.1410 -5.818 1 0.0486 170.953 4 0.6870
23 Jerk It Out 62 195666 0.017100 0.580 0.981 0.000011 8 0.3860 -2.603 0 0.0600 134.007 4 0.8610
24 Uprising 77 304840 0.000202 0.602 0.905 0.064000 2 0.1170 -4.046 1 0.0775 128.019 4 0.4110
25 Hey There Delilah 79 232533 0.872000 0.657 0.291 0.000000 2 0.1140 -10.572 1 0.0293 103.973 4 0.2980
26 Blurry 28 303920 0.010200 0.440 0.932 0.000000 3 0.1420 -4.488 0 0.0584 157.438 4 0.4950
27 American Idiot 78 176346 0.000026 0.380 0.988 0.000079 1 0.3680 -2.042 1 0.0639 186.113 4 0.7690
28 Welcome to the Black Parade 77 311106 0.000289 0.217 0.905 0.000110 2 0.2220 -4.103 1 0.0752 96.950 4 0.2360
29 Gives You Hell 71 213106 0.015600 0.714 0.725 0.000000 4 0.0726 -6.411 1 0.0402 99.988 4 0.5900
30 All My Life 11 262733 0.000194 0.582 0.597 0.000273 5 0.5170 -5.671 1 0.0512 167.738 4 0.6740
31 Like a Stone 77 293960 0.007970 0.614 0.568 0.000000 7 0.0997 -5.477 0 0.0276 107.849 4 0.5160
32 It's Been Awhile 65 264706 0.001890 0.509 0.774 0.000549 6 0.1430 -4.054 1 0.0338 116.529 4 0.0824
33 I Hate Everything About You 75 231480 0.004610 0.498 0.830 0.000000 6 0.1390 -5.157 0 0.0421 89.342 4 0.4530
34 Rollin' (Air Raid Vehicle) 74 213760 0.005060 0.599 0.932 0.000000 9 0.2690 -3.328 1 0.1800 96.234 4 0.6920
35 Fat Lip 74 178266 0.000618 0.574 0.911 0.000000 9 0.0769 -5.176 1 0.0715 98.075 4 0.5730
36 The Pretender 11 269373 0.000917 0.433 0.959 0.000000 9 0.0280 -4.040 1 0.0431 172.984 4 0.3650
37 Savior 73 242280 0.001640 0.549 0.930 0.000067 5 0.3900 -3.468 0 0.0487 112.447 4 0.5260
38 Bodies 74 201960 0.003470 0.656 0.932 0.001470 4 0.1440 -3.405 0 0.0708 130.936 4 0.5440
39 Sugar, We're Goin Down 79 229093 0.008980 0.499 0.824 0.000000 7 0.1630 -4.741 1 0.0794 161.977 4 0.6990
40 Last Nite 70 193373 0.022300 0.624 0.899 0.000155 0 0.0975 -5.710 1 0.0295 104.055 4 0.7970
41 Through Glass 60 282946 0.041700 0.545 0.753 0.000000 3 0.3890 -4.618 0 0.0360 105.754 4 0.4340
42 The Diary of Jane - Single Version 69 200546 0.000055 0.374 0.961 0.083400 10 0.1380 -4.421 0 0.0851 167.032 4 0.3570
43 Down With the Sickness 73 279213 0.000996 0.695 0.876 0.000007 3 0.1060 -4.262 0 0.0553 89.954 4 0.9410
44 Wish You Were Here 62 212733 0.000631 0.246 0.768 0.301000 9 0.1020 -7.480 1 0.0387 169.873 4 0.3500
45 Youth Of The Nation 72 256240 0.008340 0.563 0.860 0.010600 8 0.3900 -7.533 1 0.0621 97.867 4 0.5170
46 Vertigo 57 194520 0.000153 0.391 0.831 0.001920 2 0.1410 -3.892 1 0.0613 139.946 4 0.6830
47 Miss Murder 71 206586 0.000213 0.309 0.875 0.001680 1 0.1130 -4.490 1 0.0488 143.526 4 0.7250
48 I Bet You Look Good On The Dancefloor 63 173680 0.002250 0.535 0.948 0.000000 6 0.3760 -4.190 0 0.0356 103.183 4 0.7780
49 Steady, As She Goes 64 215266 0.013200 0.524 0.578 0.009210 9 0.1080 -4.563 1 0.1200 123.669 4 0.5370
In [180]:
print(data.info())
print(data.describe())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 18835 entries, 0 to 18834
Data columns (total 15 columns):
 #   Column            Non-Null Count  Dtype  
---  ------            --------------  -----  
 0   song_name         18835 non-null  object 
 1   song_popularity   18835 non-null  int64  
 2   song_duration_ms  18835 non-null  int64  
 3   acousticness      18835 non-null  float64
 4   danceability      18835 non-null  float64
 5   energy            18835 non-null  float64
 6   instrumentalness  18835 non-null  float64
 7   key               18835 non-null  int64  
 8   liveness          18835 non-null  float64
 9   loudness          18835 non-null  float64
 10  audio_mode        18835 non-null  int64  
 11  speechiness       18835 non-null  float64
 12  tempo             18835 non-null  float64
 13  time_signature    18835 non-null  int64  
 14  audio_valence     18835 non-null  float64
dtypes: float64(9), int64(5), object(1)
memory usage: 2.2+ MB
None
       song_popularity  song_duration_ms  acousticness  danceability  \
count     18835.000000      1.883500e+04  18835.000000  18835.000000   
mean         52.991877      2.182116e+05      0.258539      0.633348   
std          21.905654      5.988754e+04      0.288719      0.156723   
min           0.000000      1.200000e+04      0.000001      0.000000   
25%          40.000000      1.843395e+05      0.024100      0.533000   
50%          56.000000      2.113060e+05      0.132000      0.645000   
75%          69.000000      2.428440e+05      0.424000      0.748000   
max         100.000000      1.799346e+06      0.996000      0.987000   

             energy  instrumentalness           key      liveness  \
count  18835.000000      18835.000000  18835.000000  18835.000000   
mean       0.644995          0.078008      5.289196      0.179650   
std        0.214101          0.221591      3.614595      0.143984   
min        0.001070          0.000000      0.000000      0.010900   
25%        0.510000          0.000000      2.000000      0.092900   
50%        0.674000          0.000011      5.000000      0.122000   
75%        0.815000          0.002570      8.000000      0.221000   
max        0.999000          0.997000     11.000000      0.986000   

           loudness    audio_mode   speechiness         tempo  time_signature  \
count  18835.000000  18835.000000  18835.000000  18835.000000    18835.000000   
mean      -7.447435      0.628139      0.102099    121.073154        3.959119   
std        3.827831      0.483314      0.104378     28.714456        0.298533   
min      -38.768000      0.000000      0.000000      0.000000        0.000000   
25%       -9.044000      0.000000      0.037800     98.368000        4.000000   
50%       -6.555000      1.000000      0.055500    120.013000        4.000000   
75%       -4.908000      1.000000      0.119000    139.931000        4.000000   
max        1.585000      1.000000      0.941000    242.318000        5.000000   

       audio_valence  
count   18835.000000  
mean        0.527967  
std         0.244632  
min         0.000000  
25%         0.335000  
50%         0.527000  
75%         0.725000  
max         0.984000  
In [181]:
# Teoretyczny opis modelu regresji liniowej
print("Regresja liniowa to jedna z podstawowych technik statystycznych i uczenia maszynowego, służąca do modelowania zależności między zmienną zależną (Y) a jedną lub wieloma zmiennymi niezależnymi (X). Zakłada istnienie liniowej zależności pomiędzy tymi zmiennymi.\n")

print("Równanie regresji liniowej: y = ax +b\ny – zmienna zależna (objaśniana),\nx – zmienna niezależna (objaśniająca),\na – współczynnik kierunkowy (nachylenie prostej),\nb – wyraz wolny (punkt przecięcia z osią Y)\n")

print("Celem regresji liniowej jest znalezienie takich parametrów a i b, które minimalizują błąd przewidywań, czyli odległości między wartościami rzeczywistymi y a przewidywanymi. Służy do tego metoda najmniejszych kwadratów.")
Regresja liniowa to jedna z podstawowych technik statystycznych i uczenia maszynowego, służąca do modelowania zależności między zmienną zależną (Y) a jedną lub wieloma zmiennymi niezależnymi (X). Zakłada istnienie liniowej zależności pomiędzy tymi zmiennymi.

Równanie regresji liniowej: y = ax +b
y – zmienna zależna (objaśniana),
x – zmienna niezależna (objaśniająca),
a – współczynnik kierunkowy (nachylenie prostej),
b – wyraz wolny (punkt przecięcia z osią Y)

Celem regresji liniowej jest znalezienie takich parametrów a i b, które minimalizują błąd przewidywań, czyli odległości między wartościami rzeczywistymi y a przewidywanymi. Służy do tego metoda najmniejszych kwadratów.
In [182]:
import matplotlib.pyplot as plt

plt.scatter(data['energy'], data['loudness'])
plt.xlabel("Energy")
plt.ylabel("Loudness")
plt.title("Zależność między Energią a Głośnością")
plt.show()
No description has been provided for this image
In [183]:
import seaborn as sns
subset = data.iloc[:, :12]

sns.pairplot(subset)
plt.show()
C:\Users\A\.conda\envs\tum_py313\Lib\site-packages\seaborn\_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.
  with pd.option_context('mode.use_inf_as_na', True):
C:\Users\A\.conda\envs\tum_py313\Lib\site-packages\seaborn\_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.
  with pd.option_context('mode.use_inf_as_na', True):
C:\Users\A\.conda\envs\tum_py313\Lib\site-packages\seaborn\_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.
  with pd.option_context('mode.use_inf_as_na', True):
C:\Users\A\.conda\envs\tum_py313\Lib\site-packages\seaborn\_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.
  with pd.option_context('mode.use_inf_as_na', True):
C:\Users\A\.conda\envs\tum_py313\Lib\site-packages\seaborn\_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.
  with pd.option_context('mode.use_inf_as_na', True):
C:\Users\A\.conda\envs\tum_py313\Lib\site-packages\seaborn\_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.
  with pd.option_context('mode.use_inf_as_na', True):
C:\Users\A\.conda\envs\tum_py313\Lib\site-packages\seaborn\_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.
  with pd.option_context('mode.use_inf_as_na', True):
C:\Users\A\.conda\envs\tum_py313\Lib\site-packages\seaborn\_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.
  with pd.option_context('mode.use_inf_as_na', True):
C:\Users\A\.conda\envs\tum_py313\Lib\site-packages\seaborn\_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.
  with pd.option_context('mode.use_inf_as_na', True):
C:\Users\A\.conda\envs\tum_py313\Lib\site-packages\seaborn\_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.
  with pd.option_context('mode.use_inf_as_na', True):
C:\Users\A\.conda\envs\tum_py313\Lib\site-packages\seaborn\_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.
  with pd.option_context('mode.use_inf_as_na', True):
No description has been provided for this image
In [184]:
import statsmodels.api as sm

data_clean = data[['energy', 'loudness']].replace([np.inf, -np.inf], np.nan).dropna()

X = data_clean['energy']
Y = data_clean['loudness']

# wyraz wolny
X = sm.add_constant(X)

# Budowa modelu
model = sm.OLS(Y, X).fit()

predictions = model.predict(X)

print(model.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:               loudness   R-squared:                       0.571
Model:                            OLS   Adj. R-squared:                  0.571
Method:                 Least Squares   F-statistic:                 2.505e+04
Date:                Fri, 16 May 2025   Prob (F-statistic):               0.00
Time:                        14:18:16   Log-Likelihood:                -44042.
No. Observations:               18835   AIC:                         8.809e+04
Df Residuals:                   18833   BIC:                         8.810e+04
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const        -16.1598      0.058   -278.599      0.000     -16.273     -16.046
energy        13.5076      0.085    158.261      0.000      13.340      13.675
==============================================================================
Omnibus:                     5442.816   Durbin-Watson:                   1.261
Prob(Omnibus):                  0.000   Jarque-Bera (JB):            25971.752
Skew:                          -1.328   Prob(JB):                         0.00
Kurtosis:                       8.103   Cond. No.                         6.68
==============================================================================

Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
In [185]:
print("Interpretacja wyników:\n")
print("Dopasowanie modelu:")
print("R-squared: 0.571  - (Współczynnik determinacji) - Model tłumaczy 57,1% zmienności zmiennej loudness za pomocą zmiennej energy. To oznacza umiarkowane dopasowanie modelu.")
print("Adj. R-squared: 0.571 - (Skorygowany R²) - Używany przy wielu zmiennych — tutaj równy R², bo model ma tylko jedną zmienną niezależną.")
print("F-statistic: 25050 - (Statystyka F) - Pokazuje, że model jako całość jest istotny statystycznie.")
print("Prob (F-statistic): 0.000 - (p-wartość testu F) - Bardzo niska (0.000) — wskazuje, że model jest statystycznie istotny.")
print("Parametry modelu:")
print("const: -16.1598 - To wyraz wolny (intercept) – głośność (loudness) przy energy = 0. Ma wartość ujemną, co oznacza bardzo cichą lub brak dźwięku")
print("energy: 13.5076 - To nachylenie (slope) – pokazuje, że gdy energia wzrasta o 1 jednostkę, loudness rośnie średnio o 13.51 jednostki. Silna dodatnia zależność.")
print("Omnibus: 5442.816 oraz Prob(Omnibus): 0.000 - Test normalności reszt - Reszty nie są rozkładem normalnym (oznacza możliwe naruszenie jednego z założeń regresji).")
print("Skew: -1.328 - Skośność rozkładu reszt - Ujemna skośność – ogon po lewej stronie, może sugerować nieliniowość lub wartości odstające.")
print("Kurtosis: 8.103 - Kurtoza (spłaszczenie) - Rozkład bardziej spiczasty niż normalny (kurtosis > 3), również oznaka nienormalności.")
print("Durbin-Watson: 1.261 - Test autokorelacji reszt - Idealnie powinno być zbliżone do 2. Tutaj < 2, więc może występować autokorelacja dodatnia – reszty są zależne.")
Interpretacja wyników:

Dopasowanie modelu:
R-squared: 0.571  - (Współczynnik determinacji) - Model tłumaczy 57,1% zmienności zmiennej loudness za pomocą zmiennej energy. To oznacza umiarkowane dopasowanie modelu.
Adj. R-squared: 0.571 - (Skorygowany R²) - Używany przy wielu zmiennych — tutaj równy R², bo model ma tylko jedną zmienną niezależną.
F-statistic: 25050 - (Statystyka F) - Pokazuje, że model jako całość jest istotny statystycznie.
Prob (F-statistic): 0.000 - (p-wartość testu F) - Bardzo niska (0.000) — wskazuje, że model jest statystycznie istotny.
Parametry modelu:
const: -16.1598 - To wyraz wolny (intercept) – głośność (loudness) przy energy = 0. Ma wartość ujemną, co oznacza bardzo cichą lub brak dźwięku
energy: 13.5076 - To nachylenie (slope) – pokazuje, że gdy energia wzrasta o 1 jednostkę, loudness rośnie średnio o 13.51 jednostki. Silna dodatnia zależność.
Omnibus: 5442.816 oraz Prob(Omnibus): 0.000 - Test normalności reszt - Reszty nie są rozkładem normalnym (oznacza możliwe naruszenie jednego z założeń regresji).
Skew: -1.328 - Skośność rozkładu reszt - Ujemna skośność – ogon po lewej stronie, może sugerować nieliniowość lub wartości odstające.
Kurtosis: 8.103 - Kurtoza (spłaszczenie) - Rozkład bardziej spiczasty niż normalny (kurtosis > 3), również oznaka nienormalności.
Durbin-Watson: 1.261 - Test autokorelacji reszt - Idealnie powinno być zbliżone do 2. Tutaj < 2, więc może występować autokorelacja dodatnia – reszty są zależne.
In [186]:
# Sprawdzenie założeń modelu
from scipy.stats import normaltest

# Normalność reszt
residuals = model.resid
sns.histplot(residuals, kde=True)
plt.title("Histogram reszt")
plt.show()

stat, p = normaltest(residuals)
print(f"Normal test: stat={stat:.3f}, p={p:.3f}")
print(f" p = {p:.3f} co jest mniejsze niż 0.05 więc reszty zdecydowanie nie są z rozkładu normalnego")
C:\Users\A\.conda\envs\tum_py313\Lib\site-packages\seaborn\_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.
  with pd.option_context('mode.use_inf_as_na', True):
No description has been provided for this image
Normal test: stat=5442.816, p=0.000
 p = 0.000 co jest mniejsze niż 0.05 więc reszty zdecydowanie nie są z rozkładu normalnego
In [187]:
# Homoskedastyczność (stałość wariancji reszt)

fitted_vals = model.fittedvalues
plt.scatter(fitted_vals, residuals)
plt.axhline(0, color='red')
plt.title("Reszty vs przewidywane wartości")
plt.xlabel("Przewidywane")
plt.ylabel("Reszty")
plt.show()

print("Jak widać na wykresie punkty są rozsiane losowo wokół linii 0.\nBrak wyraźnego wzoru (brak rosnącej/malejącej wariancji z wyjątkiem początkowych wartości).\nRozrzut punktów jest w miarę stały w całym zakresie wartości przewidywanych.")
No description has been provided for this image
Jak widać na wykresie punkty są rozsiane losowo wokół linii 0.
Brak wyraźnego wzoru (brak rosnącej/malejącej wariancji z wyjątkiem początkowych wartości).
Rozrzut punktów jest w miarę stały w całym zakresie wartości przewidywanych.
In [188]:
from statsmodels.stats.stattools import durbin_watson

# Autokorelacja reszt (Durbin-Watson)
dw = durbin_watson(residuals)
print(f"Durbin-Watson = {dw:.2f}")
print("Wynik < 2 sugeruje dodatnią autokorelację. Może to oznaczać, że w danych jest jakiś trend, którego model nie uwzględnił")
Durbin-Watson = 1.26
Wynik < 2 sugeruje dodatnią autokorelację. Może to oznaczać, że w danych jest jakiś trend, którego model nie uwzględnił
In [189]:
# Współliniowość (korelacje)

sns.heatmap(data_clean[['energy', 'loudness']].corr(), annot=True, cmap='coolwarm')
plt.title("Korelacja: energy vs loudness")
plt.show()

print("Macierz wskazuje na silną dodatną korelację > 0.7")
No description has been provided for this image
Macierz wskazuje na silną dodatną korelację > 0.7
In [190]:
# Wartości odstające i wpływowe
sns.boxplot(x=residuals)
plt.title("Boxplot reszt")
plt.show()

print("Pudełko (box) – obejmuje 50% danych, od pierwszego (Q1) do trzeciego kwartylu (Q3).")
print("Linia w środku pudełka – to mediana (czyli środkowa wartość)")
print("„Wąsy” (whiskers) – sięgają do wartości w zakresie Q1 − 1.5×IQR i Q3 + 1.5×IQR.")
print("Punkty poza wąsami – to wartości odstające (outliers), czyli reszty znacznie odbiegające od większości.")
No description has been provided for this image
Pudełko (box) – obejmuje 50% danych, od pierwszego (Q1) do trzeciego kwartylu (Q3).
Linia w środku pudełka – to mediana (czyli środkowa wartość)
„Wąsy” (whiskers) – sięgają do wartości w zakresie Q1 − 1.5×IQR i Q3 + 1.5×IQR.
Punkty poza wąsami – to wartości odstające (outliers), czyli reszty znacznie odbiegające od większości.
In [191]:
influence = model.get_influence()
(c, p) = influence.cooks_distance

# Wykres odległości Cooka
plt.stem(np.arange(len(c)), c, markerfmt=",")
plt.title("Odległość Cooka")
plt.xlabel("Obserwacja")
plt.ylabel("Cook's Distance")
plt.show()

# Usunięcie wpływowych punktów (np. > 4/n)
influential_points = np.where(c > 2 / len(X))[0]
data_cleaned = data.drop(data.index[influential_points])
No description has been provided for this image
In [192]:
X_clean = data_cleaned['energy']
y_clean = data_cleaned['loudness']
X_clean = sm.add_constant(X_clean)
model_clean = sm.OLS(y_clean, X_clean).fit()
print(model_clean.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:               loudness   R-squared:                       0.635
Model:                            OLS   Adj. R-squared:                  0.635
Method:                 Least Squares   F-statistic:                 2.903e+04
Date:                Fri, 16 May 2025   Prob (F-statistic):               0.00
Time:                        14:18:20   Log-Likelihood:                -32436.
No. Observations:               16710   AIC:                         6.488e+04
Df Residuals:                   16708   BIC:                         6.489e+04
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const        -14.7672      0.049   -304.172      0.000     -14.862     -14.672
energy        11.8661      0.070    170.388      0.000      11.730      12.003
==============================================================================
Omnibus:                      278.940   Durbin-Watson:                   1.565
Prob(Omnibus):                  0.000   Jarque-Bera (JB):              278.357
Skew:                          -0.294   Prob(JB):                     3.59e-61
Kurtosis:                       2.770   Cond. No.                         7.81
==============================================================================

Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
In [193]:
clean_residuals = model_clean.resid
sns.boxplot(x=clean_residuals)
plt.title("Boxplot reszt po usunięciu wartości wpływowych")
plt.show()
No description has been provided for this image
In [194]:
influence = model_clean.get_influence()
(c, p) = influence.cooks_distance

# Wykres odległości Cooka
plt.stem(np.arange(len(c)), c, markerfmt=",")
plt.title("Odległość Cooka po sunięciu wartości wpływowych")
plt.xlabel("Obserwacja")
plt.ylabel("Cook's Distance")
plt.show()
No description has been provided for this image
In [195]:
plt.scatter(data_cleaned['energy'], data_cleaned['loudness'])
plt.xlabel("Energy")
plt.ylabel("Loudness")
plt.title("Zależność między Energią a Głośnością po usun. wart. wpływowych")
Out[195]:
Text(0.5, 1.0, 'Zależność między Energią a Głośnością po usun. wart. wpływowych')
No description has been provided for this image
In [196]:
# Normalność reszt
sns.histplot(clean_residuals, kde=True)
plt.title("Histogram reszt po usunięciu wartości wpływowych")
plt.show()

stat, p = normaltest(clean_residuals)
print(f"Normal test: stat={stat:.3f}, p={p:.3f}")
C:\Users\A\.conda\envs\tum_py313\Lib\site-packages\seaborn\_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.
  with pd.option_context('mode.use_inf_as_na', True):
No description has been provided for this image
Normal test: stat=278.940, p=0.000
In [197]:
# Homoskedastyczność (stałość wariancji reszt)

fitted_vals = model_clean.fittedvalues
plt.scatter(fitted_vals, clean_residuals)
plt.axhline(0, color='red')
plt.title("Reszty vs przewidywane wartości po usunięciu wartości wpływowych")
plt.xlabel("Przewidywane")
plt.ylabel("Reszty")
plt.show()
No description has been provided for this image
In [198]:
dw = durbin_watson(clean_residuals)
print(f"Durbin-Watson = {dw:.2f}")
print("Wynik < 2 sugeruje dodatnią autokorelację.")
Durbin-Watson = 1.57
Wynik < 2 sugeruje dodatnią autokorelację.
In [199]:
# Współliniowość (korelacje)

sns.heatmap(data_cleaned[['energy', 'loudness']].corr(), annot=True, cmap='coolwarm')
plt.title("Korelacja: energy vs loudness po usunięciu wart. wpływowych")
plt.show()

print("widać poprawę korelacji = 0.8")
No description has been provided for this image
widać poprawę korelacji = 0.8
In [200]:
from sklearn.model_selection import KFold
import statsmodels.api as sm
import numpy as np

kf = KFold(n_splits=5, shuffle=True, random_state=42)

X_clean = data_cleaned['energy']
y_clean = data_cleaned['loudness']

r2_train_list = []
r2_test_list = []
rse_train_list = []
rse_test_list = []

for train_index, test_index in kf.split(X_clean):
    X_train, X_test = X_clean.iloc[train_index], X_clean.iloc[test_index]
    y_train, y_test = y_clean.iloc[train_index], y_clean.iloc[test_index]

    X_train_const = sm.add_constant(X_train)
    X_test_const = sm.add_constant(X_test)

    model = sm.OLS(y_train, X_train_const).fit()

    y_train_pred = model.predict(X_train_const)
    y_test_pred = model.predict(X_test_const)

    r2_train = model.rsquared
    r2_test = 1 - np.sum((y_test - y_test_pred)**2) / np.sum((y_test - np.mean(y_test))**2)

    rse_train = np.sqrt(np.mean((y_train - y_train_pred)**2))
    rse_test = np.sqrt(np.mean((y_test - y_test_pred)**2))

    r2_train_list.append(r2_train)
    r2_test_list.append(r2_test)
    rse_train_list.append(rse_train)
    rse_test_list.append(rse_test)

print("Średnie R^2 (trening):", np.mean(r2_train_list))
print("Średnie R^2 (test):", np.mean(r2_test_list))
print("Średnie RSE (trening):", np.mean(rse_train_list))
print("Średnie RSE (test):", np.mean(rse_test_list))

print("Podsumowanie:\nModel działa stabilnie - błędy są podobne na zbiorze treningowym i testowym.\nModel nie jest przeuczony co sugeruje RSE.\nR^2 (R-squared) = 0.63 oznacza, że model wyjaśnia ~63% zmienności loudness na podstawie energy. Ma średnie dopasowanie ale może to wynikać z faktu że dane które analizujemy nie były idealnie liniowe.")
Średnie R^2 (trening): 0.6347230452604158
Średnie R^2 (test): 0.6345889431517886
Średnie RSE (trening): 1.6856341906057757
Średnie RSE (test): 1.6857654494805416
Podsumowanie:
Model działa stabilnie - błędy są podobne na zbiorze treningowym i testowym.
Model nie jest przeuczony co sugeruje RSE.
R^2 (R-squared) = 0.63 oznacza, że model wyjaśnia ~63% zmienności loudness na podstawie energy. Ma średnie dopasowanie ale może to wynikać z faktu że dane które analizujemy nie były idealnie liniowe.